home *** CD-ROM | disk | FTP | other *** search
- /*
- * MDCFS: Minimal Dos Compatible File System
- *
- * These routines provide the bare minimum needed to read and write
- * files on an MS-DOS format floppy disk. You could use them with a hard
- * disk as well, however since only 12 bit FAT's are supported, you are
- * limited to a total of 4096 clusters, and total drive space is limited
- * to 32MB due to 16 bit sector numbers (assuming 512 byte sectors).
- *
- * The functions were written for use in embedded systems (where memory
- * is often limited), and therefore provide only the basic open, read/write,
- * close and delete operations. I have documented the functions which
- * manipulate the directory and FAT, and it should be fairly easy to add
- * other features if you need them (directory display etc.). Only access to
- * files in the ROOT directory is provided, subdirectories are NOT supported.
- *
- * For simplicity and memory conservation, these functions buffer only 1
- * sector (512 bytes) in memory. This makes them run quite slowly, but is
- * adaquate for reading/writing setup information and occational data logging.
- * If you have lots of memory and need extra speed, you could modify the
- * functions to read/write multiple sectors (a cluster would be easy).
- * You can also experiment with different interleave factors, to obtain
- * optimim performance with the existing I/O functions.
- *
- * As they stand, the functions really support access to only one drive
- * at a time. You can use multiple drives if you call "open_drive()" between
- * disk operations to the separate drives. This "switches" the active drive
- * to the specified one. Note however, that the selected drive will seek to
- * track zero each time this function is called, so performing many small
- * operations on more than one drive gets VERY inefficent. DO NOT read or
- * write to an open file located on any drive other than the currently
- * selected one! Call "open_drive()" first!
- *
- * Concurrent access to multiple files (on the same drive) is supported,
- * however since only one "work" buffer is used for directory/FAT access,
- * the drive may have to perform extra read/write operation when switching
- * from one file to the other. For this reason, it is best to try and do
- * as many reads or writes as possible on one file before accessing others.
- * Avoid many small operations to multiple files.
- *
- * At present, only the first copy of the disk File Allocation Table
- * (FAT) is used by these functions.
- *
- * Functions read/write data in RAW (binary) form, without regard for
- * NEWLINE characters etc. If you want to read/write ASCII text, you will
- * have to write "wrapper" functions to drop RETURN (0x0D) characters on
- * reading, and to add them before NEWLINE (0x0A) when writing.
- *
- * Due to the use of 'C' structures, Version 3.0 (or later) of MICRO-C
- * is REQUIRED! It should not be difficult to compile with a different
- * compiler, but I have not attempted to do so.
- *
- * Copyright 1993-1994 Dave Dunfield
- * All rights reserved.
- *
- * Permission granted for personal (non-commercial) use only.
- */
-
-
- /* Required definitions from MICRO-C stdio.h (not part of MDCFS) */
- extern register printf();
- #define FILE unsigned
-
-
- /* Misc fixed parameters */
- #define SECTOR_SIZE 512 /* Size of a disk sector */
- #define BPB_SIZE 17 /* Number of bytes in BIOS Parm Block */
- #define EMPTY 0xE5 /* Signals empty directory */
- #define EOF -1 /* End of file indicator */
- #define ERROR -2 /* Report error in file */
- #define READ 0 /* File opened for READ */
- #define WRITE 1 /* File opened for WRITE */
-
-
- /*
- * Structure of MSDOS directory entry
- */
- struct Dentry {
- unsigned char Dname[11]; /* Filename + extension */
- unsigned char Dattr; /* File attributes */
- unsigned char Dreserved[10]; /* Reserved area */
- unsigned Dtime; /* Time last modified */
- unsigned Ddata; /* Date last modified */
- unsigned Dcluster; /* First cluster number */
- unsigned Dsizel; /* File size (LOW) */
- unsigned Dsizeh; } ; /* File size (HIGH) */
-
- /*
- * Structure of internal file control block
- */
- struct Fblock {
- unsigned char Fattr; /* Open attributes */
- unsigned char Fsector; /* Sector within cluster */
- struct Dentry *Fdirptr; /* Pointer to directory entry */
- unsigned Fdirsec; /* Directory sector */
- unsigned Ffirstcls; /* First cluster in file */
- unsigned Flastcls; /* Last cluster read/written */
- unsigned Fnextcls; /* Next cluster to read/write */
- unsigned Foffset; /* Read/Write offset */
- unsigned Fsizel; /* File size (LOW) */
- unsigned Fsizeh; /* File size (HIGH) */
- unsigned char Fbuffer[]; } ; /* Data transfer buffer */
-
-
- /* Internal "work" sector variables */
- unsigned wrkdrv = 0, /* Current work drive number */
- wrksec = -1; /* Current work sector number */
- char wrkchg = 0; /* Indicates work sector changed */
- unsigned char wrkbuff[SECTOR_SIZE]; /* Work sector buffer */
-
- /* Active drive information (other than contained in BPB) */
- char active_drive = -1; /* Open disk drive number */
- unsigned dirsec = 5, /* First sector of directory */
- datasec = 12; /* First sector of data area */
-
- /* Disk information (from BIOS Parameter Block) */
- unsigned int bytsec = 512; /* Bytes / sector */
- unsigned char seccls = 2; /* Sectors / cluster */
- unsigned int ressec = 1; /* # reserved sectors */
- unsigned char numfat = 2; /* Number of FAT's */
- unsigned int dirent = 112; /* Number of directory entries */
- unsigned int sectors = 720; /* Sectors on disk */
- unsigned char mediaid = 0xFD; /* Media ID byte */
- unsigned int secfat = 2; /* Sectors / fat */
- unsigned int sectrk = 9; /* Sectors / track */
- unsigned int numhead = 2; /* Number of heads */
-
-
- /*
- * Function Prototypes
- */
- extern struct Dentry *lookup(), *create_file();
-
-
- /*
- * File accessing functions:
- *
- * open_drive(drive) - Initialize a drive for file access
- * drive - Drive id (0=A, 1=B ...)
- *
- * open_file(name, attrs) - Open file for read or write
- * name - Name of file to open
- * attrs - Open attributes: READ or WRITE
- * returns : Pointer to file structure, or 0 if failure
- *
- * close_file(fp) - Close an open file
- * fp - Pointer to open file structure
- *
- * read_byte(fp) - Read a byte from an open file
- * fp - Pointer to open file structure
- * returns : Value read (0-255), -1 if EOF, -2 if not open for read
- *
- * write_byte(byte, fp) - Write a byte to a file
- * byte - Value to write to file (0-255)
- * returns : Value written (0-255) or -2 if error
- *
- * delete_file(name) - Erases the named file
- * name - Name of file to erase
- * returns : 0 if Success, -1 if failure (file not found)
- */
-
- /*
- * Open a disk drive and set up control information
- *
- * THIS FUNCTION MUST BE CALLED BEFORE ACCESSING ANY FILES,
- * AND ANYTIME YOU SWITCH TO ACCESS A DIFFERENT DRIVE.
- */
- open_drive(drive)
- char drive;
- {
- read_work(active_drive = drive, 0);
- memcpy(&bytsec, wrkbuff+11, BPB_SIZE);
- dirsec = (numfat * secfat) + ressec;
- datasec = ((((dirent * sizeof(struct Dentry)) + bytsec) - 1) / bytsec) + dirsec;
- }
-
- /*
- * Open a file & return a pointer to an allocated file structure
- */
- struct Fblock *open_file(name, attrs)
- char *name;
- int attrs;
- {
- struct Dentry *dirptr;
- struct Fblock *fp;
-
- if(dirptr = lookup(name)) { /* File already exists */
- if(attrs == WRITE) /* Zero size on write */
- dirptr->Dsizel = dirptr->Dsizeh = 0; }
- else {
- if(attrs != WRITE) /* Not writing file */
- return 0;
- if(!(dirptr = create_file(name, 0))) /* Unable to create */
- return 0; }
-
- /* Allocate buffer for file control block */
- if(!(fp = malloc(bytsec+sizeof(struct Fblock))))
- return 0;
-
- /* Fill in file control block from directory information */
- fp->Fdirsec = wrksec;
- fp->Fdirptr = dirptr;
- fp->Fattr = attrs;
- fp->Fnextcls = fp->Ffirstcls = dirptr->Dcluster;
- fp->Fsizel = dirptr->Dsizel;
- fp->Fsizeh = dirptr->Dsizeh;
- fp->Fsector = fp->Foffset = fp->Flastcls = 0;
-
- return fp;
-
- }
-
- /*
- * Close an open file
- */
- close_file(fp)
- struct Fblock *fp;
- {
- struct Dentry *dirptr;
- unsigned sizeh, sizel;
-
- /* Special actions to be taken when writing */
- if(fp->Fattr == WRITE) {
- sizel = fp->Fsizel;
- sizeh = fp->Fsizeh;
- /* If there is a partial last sector, fill it with DOS EOF */
- /* characters, which also causes it to be written out */
- while(fp->Foffset)
- write_byte(0x1A, fp);
- /* Release remaining clusters in file. If any sectors in the */
- /* current cluster are used, begin with the next one. */
- release(fp->Fsector ? get_fat(fp->Fnextcls) : fp->Fnextcls);
- /* Update size entry in file directory */
- read_work(active_drive, fp->Fdirsec);
- dirptr = fp->Fdirptr;
- dirptr->Dcluster= fp->Ffirstcls;
- dirptr->Dsizel = sizel;
- dirptr->Dsizeh = sizeh;
- /* Set directory date of modification here - if you wish */
- wrkchg = -1; }
-
- free(fp);
-
- update_work(); /* Insure disk is in sync */
- }
-
- /*
- * Delete a file from the disk
- */
- delete_file(name)
- char *name;
- {
- struct Dentry *dirptr;
-
- if(dirptr = lookup(name)) {
- *dirptr->Dname = EMPTY;
- wrkchg = -1;
- release(dirptr->Dcluster);
- update_work();
- return 0; }
- return -1;
- }
-
- /*
- * Read next byte from open file
- */
- int read_byte(fp)
- struct Fblock *fp;
- {
- unsigned cluster, sector;
-
- /* If all data read, return EOF */
- if(!(fp->Fsizel || fp->Fsizeh)) {
- return EOF; }
-
- /* Decrement file size (32 bit) */
- if((--fp->Fsizel) == -1)
- --fp->Fsizeh;
-
- /* If no data buffered ... read next sector */
- if((fp->Foffset >= bytsec) || !fp->Foffset) {
- /* If not open for READ, return ERROR */
- if(fp->Fattr != READ)
- return ERROR;
-
- /* If past last cluster, return EOF */
- if(((cluster = fp->Fnextcls) >= 0xFF8) || !cluster)
- return EOF;
-
- /* Read the sector into memory */
- read_sector(active_drive,
- (sector = fp->Fsector) + ((cluster-2)*seccls) + datasec,
- fp->Fbuffer);
-
- /* Advance sector in cluster, if past end, get next cluster number */
- if(++sector >= seccls) {
- fp->Fnextcls = get_fat(cluster);
- sector = 0; }
-
- /* Update file control block information */
- fp->Flastcls = cluster;
- fp->Fsector = sector;
- fp->Foffset = 0; }
-
- /* Read character, and advance circular buffer pointer */
- return fp->Fbuffer[fp->Foffset++];
- }
-
- /*
- * Write a byte to an open file
- */
- int write_byte(c, fp)
- unsigned c;
- struct Fblock *fp;
- {
- unsigned cluster, sector;
-
- /* Test for writable file */
- if(fp->Fattr != WRITE)
- return ERROR;
-
- /* Advance file size */
- if(!++fp->Fsizel)
- ++fp->Fsizeh;
-
- /* Write character to buffer */
- fp->Fbuffer[fp->Foffset++] = c;
-
- /* If buffer is full, write it */
- if(fp->Foffset >= bytsec) {
- /* If no sector allocated, allocate one */
- if(!fp->Fnextcls)
- fp->Ffirstcls = fp->Fnextcls = allocate(0);
- else if(fp->Fnextcls >= 0xFF8)
- fp->Fnextcls = allocate(fp->Flastcls);
-
- if(!(cluster = fp->Fnextcls))
- return ERROR;
-
- /* Write the data to the drive */
- write_sector(active_drive,
- (sector = fp->Fsector) + ((cluster-2)*seccls) + datasec,
- fp->Fbuffer);
-
- /* Advance to next sector in cluster */
- if(++sector >= seccls) {
- fp->Fnextcls = get_fat(cluster);
- sector = 0; }
-
- /* Update file control block information */
- fp->Flastcls = cluster;
- fp->Fsector = sector;
- fp->Foffset = 0; }
-
- return c;
- }
-
-
- /*
- * FAT manipulation functions:
- *
- * allocate(cluster) - Allocate a free cluster
- * cluster - Cluster to link this one to (o if none).
- * returns : Cluster number allocated, 0 if failure
- *
- * release(cluster) - Release a cluster chain (if allocated)
- * cluster - Beginnig cluster to release
- *
- * get_fat(cluster) - Get FAT entry for cluster
- * cluster - Cluster number to obtain entry for
- * returns : Cluster number linked (0 if free, 0xFF8+ for EOF)
- *
- * set_fat(cluster, link) - Set the FAT entry for a cluster
- * cluster - Cluster number to set link for
- * link - Cluster number to link to (0=free, 0xFFF = EOF)
- */
-
- /*
- * Allocate a free cluster on disk, and cross connect FAT if necessary
- * mark cluster as used & end of file.
- */
- int allocate(cluster)
- int cluster;
- {
- int begin, end, i;
-
- /* Calculate start and end clusters for search */
- /* If we have a "FAT" sector loaded, begin searching from there, */
- /* To attempt to keep allocated sectors in same "FAT" sector */
-
- begin = ((i = wrksec-1) && (i <= secfat)) ?
- ((i * (SECTOR_SIZE*2)) / 3) + 1 : 2;
- end = (sectors - datasec) / seccls;
-
- do {
- #ifdef DEBUG
- printf("Allocate(%u) : Wrk=%u Begin=%u End=%u\n", cluster, wrksec, begin, end);
- #endif
- for(i = begin; i < end; ++i)
- if(!get_fat(i)) {
- #ifdef DEBUG
- printf("Allocated %u\n", i);
- #endif
- set_fat(i, 0xFFF);
- if(cluster)
- set_fat(cluster, i);
- return i; }
- /* Didn't find, reset to start cluster, and try again */
- end = begin;
- begin = 2; }
- while(end != 2);
-
- #ifdef DEBUG
- printf("Failed!\n");
- #endif
- return 0;
- }
-
- /*
- * Release a chain of allocated clusters
- */
- release(cluster)
- int cluster;
- {
- unsigned i;
- while(cluster && (cluster < 0xFF8)) {
- i = get_fat(cluster);
- set_fat(cluster, 0);
- cluster = i; }
- }
-
- /*
- * Get a FAT entry for a given cluster number
- */
- int get_fat(cluster)
- unsigned cluster;
- {
- unsigned sec, fat;
-
- #ifdef DEBUG
- printf("Get FAT for %u - ", cluster);
- #endif
-
- sec = (cluster *= 3)/2;
- read_work(active_drive, (sec / bytsec) + 1);
- fat = wrkbuff[sec % bytsec];
- read_work(active_drive, (++sec / bytsec) + 1);
- fat |= wrkbuff[sec % bytsec] << 8;
- if(cluster & 1)
- fat >>= 4;
-
- #ifdef DEBUG
- printf("%u\n", fat & 0xFFF);
- #endif
-
- return fat & 0xfff;
- }
-
- /*
- * Set a FAT entry for a given cluster number
- */
- set_fat(cluster, value)
- unsigned cluster, value;
- {
- unsigned sec, x;
-
- #ifdef DEBUG
- printf("Set FAT for %u - %u\n", cluster, value);
- #endif
-
- sec = (cluster *= 3)/2;
-
- /* Set LOW byte of FAT */
- read_work(active_drive, (sec / bytsec) + 1);
- x = sec % bytsec;
- if(cluster & 1)
- wrkbuff[x] = (wrkbuff[x] & 0x0F) | (value << 4);
- else
- wrkbuff[x] = value;
- wrkchg = -1;
-
- /* Set high byte of FAT */
- read_work(active_drive, (++sec / bytsec) + 1);
- x = sec % bytsec;
- if(cluster & 1)
- wrkbuff[x] = value >> 4;
- else
- wrkbuff[x] = (wrkbuff[x] & 0xF0) | ((value >> 8) & 0x0F);
- wrkchg = -1;
- }
-
-
- /*
- * Directory manipulation functions:
- *
- * lookup(file) - Locate a files directory entry
- * file - Name of file to locate
- * returns : Pointer to directory entry, 0 if failure.
- *
- * create_file(file,attrs) - Create a mew file
- * file - Name of file to create
- * attrs - Attributes for file (0 = normal)
- * returns : Pointer to directory entry, 0 if failure.
- *
- * parse_filename(buffer,name) - Get filename in directory format
- * buffer - Buffer for directory format filename (13 bytes)
- * name - ASCII filename to convert
- *
- * memcmp(ptr1, ptr2, size) - Block memory compare
- * ptr1 - Pointer to first block
- * ptr2 - Pointer to second block
- * size - Number of bytes to compare
- * returns : -1 of match, 0 if different.
- */
-
- /*
- * Lookup a directory entry & return pointer to it
- */
- struct Dentry *lookup(file)
- char *file;
- {
- unsigned i, j, k;
- char fbuffer[12];
-
- parse_filename(fbuffer, file);
-
- #ifdef DEBUG
- printf("Lookup: '%s' ", fbuffer);
- #endif
-
- j = bytsec;
- k = dirsec;
- for(i=0; i < dirent; ++i) {
- if(j >= bytsec) {
- read_work(active_drive, k++);
- j = 0; }
- if(memcmp(wrkbuff+j, fbuffer, 11)) {
- #ifdef DEBUG
- printf("Found - Cluster: %u\n", *(int*)(wrkbuff+j+0x1A));
- #endif
- return wrkbuff+j; }
- j += sizeof(struct Dentry); }
-
- #ifdef DEBUG
- printf("Not found\n");
- #endif
- return 0;
- }
-
- /*
- * Create a file with the specified name
- * NOTE: Does NOT check for duplicates. It is assumed that "lookup()"
- * has been called first, to verify that the file does not already
- * exist on the disk.
- */
- struct Dentry *create_file(file, attrs)
- char *file;
- int attrs;
- {
- int i, j, k;
- char fbuffer[12];
- struct Dentry *dirptr;
-
- parse_filename(fbuffer, file);
-
- #ifdef DEBUG
- printf("Create '%s' ", fbuffer);
- #endif
-
- j = bytsec;
- k = dirsec;
- for(i=0; i < dirent; ++i) {
- if(j >= bytsec) {
- read_work(active_drive, k++);
- j = 0; }
- if((*(dirptr = wrkbuff+j)->Dname == EMPTY) || !*dirptr->Dname) {
- #ifdef DEBUG
- printf("Dir entry #%u\n", i);
- #endif
- memset(dirptr, 0, sizeof(struct Dentry));
- strcpy(dirptr, fbuffer);
- dirptr->Dattr = attrs;
- /* Set directory date of creation here - if you wish */
- wrkchg = -1;
- return wrkbuff+j; }
- j += sizeof(struct Dentry); }
-
- #ifdef DEBUG
- printf("No directory!\n");
- #endif
-
- return 0;
- }
-
- /*
- * Parse a filename into directory format (12 characters, space filled)
- */
- parse_filename(buffer, name)
- char buffer[], *name;
- {
- int i;
-
- i = 0;
- while(i < 8)
- buffer[i++] = (*name && (*name != '.')) ? toupper(*name++) : ' ';
- if(*name == '.')
- ++name;
- while(i < 11)
- buffer[i++] = *name ? toupper(*name++) : ' ';
- buffer[i] = 0;
- }
-
- /*
- * Memory to memory compare
- */
- int memcmp(ptr1, ptr2, size)
- char *ptr1, *ptr2;
- unsigned size;
- {
- while(size--)
- if(*ptr1++ != *ptr2++)
- return 0;
- return -1;
- }
-
-
- /*
- * Intermal "work" sector manipulation functions:
- *
- * read_work(sector) - Read sector into work buffer (if necessary)
- * sector - Sector number to read.
- *
- * update_work() - Write work sector back to disk if changed
- */
-
- /*
- * Read a work sector into memory if it is not already in memory.
- */
- read_work(drive, sector)
- char drive;
- int sector;
- {
- if((wrkdrv != drive) || (wrksec != sector)) {
- update_work();
- read_sector(wrkdrv = drive, wrksec = sector, wrkbuff); }
- }
-
- /*
- * Write the work sector if it has been marked as modified
- */
- update_work()
- {
- if(wrkchg) {
- write_sector(wrkdrv, wrksec, wrkbuff);
- wrkchg = 0; }
- }
-
-
- /*
- * Low level disk I/O functions:
- *
- * disk_error(code) - Called if unrecoverable disk error
- * code - Disk failure code (system depandant)
- *
- * read_sector(d, s, b) - Read a sector from the disk
- * d - Drive to read (0=A, 1=B ...)
- * s - Sector number to read (1-n)
- * b - Pointer to buffer to receive data
- *
- * write_sector(d, s, b) - Write a sector to the disk
- * d - Drive to write (0=A, 1=B ...)
- * s - Sector number to write (1-n)
- * b - Pointer to buffer containing the data
- *
- * These functions make use of the IBM PC BIOS, and are compatible
- * with Microsoft MASM assembler. Use these if you are compiling the
- * demo program with the MICRO-C DOS compiler.
- */
-
- /*
- * Report a disk error
- */
- disk_error(code)
- int code;
- {
- printf("Disk error - Code: %04x\n", code);
- exit(-1);
- }
-
- /*
- * Read a sector from the disk drive
- */
- read_sector(drive, sector, buffer) asm
- {
- PUSH DS ; Save DS
- POP ES ; Set ES
- MOV BX,4[BP] ; Get buffer
- MOV AX,6[BP] ; Get sector
- XOR DX,DX ; Zero high
- DIV WORD PTR _sectrk; Calculate track
- MOV CL,DL ; CL = sector
- INC CL ; 1-
- XOR DX,DX ; Zero high
- DIV WORD PTR _numhead; Compute head
- MOV CH,AL ; CH = cylinder
- MOV DH,DL ; DH = head
- MOV DL,8[BP] ; DL = drive
- MOV DI,3 ; Try three times
- read1: MOV AX,0201h ; Read 1 sector
- INT 13h ; Call BIOS
- JNC read2 ; Success
- DEC DI ; Reduce count
- JNZ read1 ; Keep trying
- PUSH AX ; Pass parameter
- CALL _disk_error ; Report an error
- POP AX ; Clean stack
- read2: XOR AX,AX ; Zero return
- }
-
- /*
- * Write a sector to the disk drive
- */
- write_sector(drive, sector, buffer) asm
- {
- PUSH DS ; Save DS
- POP ES ; Set ES
- MOV BX,4[BP] ; Get buffer
- MOV AX,6[BP] ; Get sector
- XOR DX,DX ; Zero high
- DIV WORD PTR _sectrk; Calculate track
- MOV CL,DL ; CL = sector
- INC CL ; 1-
- XOR DX,DX ; Zero high
- DIV WORD PTR _numhead; Compute head
- MOV CH,AL ; CH = cylinder
- MOV DH,DL ; DH = head
- MOV DL,8[BP] ; DL = drive
- MOV DI,3 ; Try three times
- write1: MOV AX,0301h ; Write 1 sector
- INT 13h ; Call BIOS
- JNC write2 ; Success
- DEC DI ; Reduce count
- JNZ write1 ; Keep trying
- PUSH AX ; Pass parameter
- CALL _disk_error ; Report an error
- POP AX ; Clean stack
- write2: XOR AX,AX ; Zero return
- }
-
-
- /*
- * Sample Main program (Not part of MDCFS) to demonstrate reading,
- * writing and deleteing files. This also uses the standard file
- * I/O of the MICRO-C DOS compiler, and will not run stand-alone.
- *
- * Demo command syntax:
- * MCDFS W <file> - Copy file from current DOS dir to floppy
- * MCDFS R <file> - Copy file from floppy to current DOS dir
- * MCDFS D <file> - Delete file from floppy.
- *
- * All accesss to the floppy are performed via MCDFS.
- */
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int c;
- struct Fblock *fp;
- FILE *xfp;
-
- open_drive(0); /* Change to (1) for drive B: */
- switch((argc > 2) ? toupper(*argv[1]) : 0) {
-
- case 'R' : /* Read file from floppy drive */
- if(!(fp = open_file(argv[2], READ)))
- abort("Couldn't read MDCFS file");
- xfp = fopen(argv[2], "wbvq");
- while((c = read_byte(fp)) >= 0)
- putc(c, xfp);
- close_file(fp);
- fclose(xfp);
- c = 0; /* Disk has not been modified */
- break;
-
- case 'W' : /* Write file to floppy drive */
- xfp = fopen(argv[2], "rvbq");
- if(!(fp = open_file(argv[2], WRITE)))
- abort("Couldn't write MDCFS file");
- while((c = getc(xfp)) >= 0)
- write_byte(c, fp);
- fclose(xfp);
- close_file(fp);
- c = -1; /* Note that disk may have been written */
- break;
-
- case 'D' : /* Delete file from floppy drive */
- delete_file(argv[2]);
- c = -1; /* Note that disk may have been written */
- break;
-
- default:
- abort("Use: MDCFS (Read/Write/Delete) <filename>"); }
-
- if(c) {
- printf("\nNote: Since MDCFS bypasses DOS completely, DOS will be unaware\n");
- printf("of any changes to the disk... Due to DOS buffering, files written\n");
- printf("may not appear in DOS 'dir' command, or may have their sizes\n");
- printf("reported incorrectly... Press CONTROL-C to force DOS to flush\n");
- printf("its buffers before accessing the floppy disk"); }
- }
-